package com.core;

import hibernate.HibernateSessionFactory;

import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.CriteriaSpecification;
import org.hibernate.criterion.Projections;
import java.util.Collection;
import org.hibernate.type.Type;

import com.core.Page;



/**
 * Data access object (DAO) for domain model
 * @author MyEclipse - Hibernate Tools
 */ 
public class BaseHibernateDAO  {
	
	protected Transaction tx = null;
	
	public Session getSession() {
		try{
			return HibernateSessionFactory.getSession();
		}
		catch(Exception e){
			e.printStackTrace();
			return null;
		}
	}
	
	public Page findByCriteriaWithPage(Criteria criteria, int pageNo,
			int pageSize) {
		if (pageNo < 1) {
			pageNo = 1;
		}
		int startIndex = Page.getStartOfAnyPage(pageNo, pageSize);
		int totalCount =((Integer) criteria.setProjection(
				Projections.rowCount()).uniqueResult()).intValue();

		criteria.setProjection(null);
		List list = criteria.setFirstResult(startIndex - 1).setMaxResults(
				pageSize).list();
		int avaCount = list == null ? 0 : list.size();

		return new Page(startIndex, avaCount, totalCount, pageSize, list);
	}
	
	public Page findAllWithPage(int pageNo, int pageSize) {
		
		Session session = getSession();
		Criteria criteria = session.createCriteria(getEntityClass());
		criteria.setProjection(null);
		criteria.setResultTransformer(CriteriaSpecification.ROOT_ENTITY);
		return findByCriteriaWithPage(criteria, pageNo, pageSize);
	}
	
	public int countByHQL(String hql) {
		Query query = this.getSession().createQuery(hql);
		return ((Integer) query.uniqueResult()).intValue();
	}

	/**
	 * @see com.wondersgroup.framework.core.dao.AbstractHibernateDAO#countByHQL(java.lang.String,
	 *      List)
	 */
	public int countByHQL(String hql, List args) {
		try {
			Query query = this.getSession().createQuery(hql);
			setQueryParameters(query, args);
			return ((Integer) query.uniqueResult()).intValue();
		} catch (HibernateException ex) {
			System.out.println(ex.getMessage());
			return 0;
		}
	}

	public List findByHqlWithMaxResult(String hql, List args, int rows) {
		try {
			Query query = this.getSession().createQuery(hql);
			if (rows > 0) {
				query = query.setMaxResults(rows);
			}
			setQueryParameters(query, args);
			return query.list();
		} catch (HibernateException ex) {
			System.out.println(ex.getMessage());
			return null;
		}
	}
	
	public List findByHql(String hql, List args) {
		try {
			Query query = this.getSession().createQuery(hql);
			setQueryParameters(query, args);
			return query.list();
		} catch (HibernateException ex) {
			System.out.println(ex.getMessage());
			return null;
		}
	}
	
	/**
	 * @see com.wondersgroup.framework.core.dao.AbstractHibernateDAO#findByHQLWithPage(java.lang.String,
	 *      int, int, String)
	 */
	public Page findByHQLWithPage(String qryHql, int pageNo, int pageSize, String countHql) {
		return this.findByHQLWithPage(qryHql, null, pageNo, pageSize, countHql);
	}

	/**
	 * @see com.wondersgroup.framework.core.dao.AbstractHibernateDAO#findByHQLWithPage(java.lang.String,
	 *      List, int, int, String)
	 */
	public Page findByHQLWithPage(String qryHql, List args, int pageNo,
			int pageSize, String countHql) {
		if (qryHql == null) {
			throw new IllegalArgumentException("NULL is not a valid string");
		}
		if (countHql == null) {  // try construct a count hql statement
			countHql = "select count(*) "
				+ qryHql.substring(qryHql.indexOf(" from "));
		}
		int totalCount = this.countByHQL(countHql, args);
		if (totalCount < 1) {
			return Page.EMPTY_PAGE;
		}

		Query query = getSession().createQuery(qryHql);
		this.setQueryParameters(query, args);

		if (pageNo < 1) {
			pageNo = 1;
		}
		int startIndex = Page.getStartOfAnyPage(pageNo, pageSize);
		List list = query.setFirstResult(startIndex - 1)
				.setMaxResults(pageSize).list();
		int avaCount = (list == null) ? 0 : list.size();
		return new Page(startIndex, avaCount, totalCount, pageSize, list);
	}
	
	protected Class getEntityClass(){		
		return null;
	}
	
	
	
	/**
	 * @param query
	 * @param args
	 */
	private void setQueryParameters(Query query, List args) {
		if (args != null) {
			for (int i=0; i<args.size(); i++) {
				HqlParameter arg = (HqlParameter) args.get(i);
				String argName = arg.getName();
				Object argValue = arg.getValue();
				Type argType = arg.getType();
				
				if (argName == null) { // use position
					if (argType == null) {
						query.setParameter(i, argValue);
					} else {
						query.setParameter(i, argValue, argType);
					}
				} else {
					if (argType == null) {
						if (Collection.class.isInstance(argValue)) {
							query.setParameterList(argName, (Collection)argValue);
						} else {
							query.setParameter(argName, argValue);
						}						
					} else {
						if (Collection.class.isInstance(argValue)) {
							query.setParameterList(argName, (Collection)argValue, argType);
						} else {
							query.setParameter(argName, argValue, argType);
						}	
					}
				}
			}
		}
	}
}